import { useState } from 'react';
// import reactLogo from "./assets/react.svg";
// import viteLogo from "/vite.svg";
// import './App.css'

const setCount = () => {
  console.log('setCount');
};
// 3.绑定事件-接收参数
const setCountParams = (params, e) => {
  console.log('setCountParams');
};
// 3.绑定事件-接收参数类型是泛型
// 正常写泛型语法会跟tsx语法冲突，因为他会把泛型理解成是一个元素(把<T>理解成了一个元素<div>)，解决方案 T后面加一个,即可（纠正泛型 <T,>）
const setCountT = <T,>(params: T) => {
  console.log(params, 'setCountT');
};
function App() {
  // const [count, setCount] = useState(0);
  // tsx语法
  // 1.绑定变量：插值语句  {}
  // 2.插件语句支持对象怎么弄  let obj = {name: 'zhangsan'} 会报错；需要进行序列化  JSON.stringify(obj)
  // 3.绑定事件  驼峰 onClick
  //   接收参数注意 ：<button onClick={setCount(123)}>  这样写刷面页面就会自动触发一次,需要使用高阶函数。如果不需要直接把函数体丢过去即可。
  //               传参正确写法：<button onClick={(e)=>setCountParams(123,e)}></button>
  //   支持泛型函数 <button onClick={(e)=>setCountT('aaaa')}></button>
  // 4.dom元素绑定id、class 属性，记得class是属性 className来添加类属性，不是class。如何添加多个类名？使用模板字符串来添加类名即可。
  // 5.渲染html字符串, 属性dangerouslySetInnerHTML={{__html: '<h1>123</h1>'}}
  const id: string = '111';
  const className: string = 'new';
  const htmlString: string = '<h1>123</h1>';
  // 6.遍历dom元素 即对比vue的v-for
  const arr: { id: number; name: string }[] = [
    { id: 1, name: '遍历dom元素' },
    { id: 2, name: 'lisi' },
  ];
  const [str, setStr] = useState('test');
  const [bool, setBool] = useState(true);
  const [list, setList] = useState(['大,', '中,', '小,']);
  const [num, setListNum] = useState([1, 2, 3]);
  // const [obj, setObj] = useState({ name: 'zhangsan', age: 18, date: '2021-09-01' });
  // 不仅可以存储纯对象类型，还可以存储一个函数，函数里面方便做一些初始化操作，但函数只执行一次，比如日期
  const [obj, setObj] = useState(() => {
    const date = new Date().getFullYear() + '-' + (new Date().getMonth() + 1) + '-' + new Date().getDate();
    return {
      name: 'zhangsan',
      age: 18,
      date,
    };
  });

  const handleClick = () => {
    setStr('111');
  };

  const handleClickBool = () => {
    setBool(!bool);
  };

  const handleClickList = (type?: string) => {
    if (type === 'sort') {
      // 排序
      const arr1 = [...num];
      arr1.sort((a, b) => b - a);
      setListNum(arr1);
      console.log(num, 'num');
      return;
    }
    // list.push('特大')
    // setList(list);  视图不会发生改变，但数据变了
    // 原因：在React中你需要将数组视为只读的，不可以直接修改原数组。可以使用返回新的数组方法(concat/filter/map等) 或者先拷贝一份数组再修改
    // setList([...list]);  视图会发生改变，数据也变了  => 因为...list拷贝了一份
    // 增
    // const arr = [...list, '特大']
    // 删--或者slice
    // const arr = list.filter(item => item !== '大,');
    // 改（替换）
    // const arr = list.map(item => item === '大,' ? '特大,' : item);
    // 改（大后面插入'中大'） slice(start, end) 从start开始，到end结束，不包括end
    // const arr = [...list.slice(0, 1), '中大,', ...list.slice(1)];
    // 反转数组
    const arr = [...list];
    arr.reverse();
    setList(arr);
    // 注意此时拷打印的值没有变化！因为set函数是异步的，log是同步的先输出初始值。详看useState的更新机制
    console.log(list);
  };

  const handleClickObj = () => {
    // 函数return一个对象，所以必须传入一个对象
    // setObj({ ...obj, name: 'susan' });
    setObj(Object.assign({}, obj, { name: 'susan' }));
  };

  console.log('组件渲染');
  const [index, setIndex] = useState(0);
  const handleClickIndex = () => {
    // 1.异步-react的性能优化
    // setIndex(1);
    // console.log(index, 'index'); // 输出是初始值（上一个的值），因为set函数是异步的,log是同步的
    // 2.性能优化的体现。关注视图的值和console.log('组件渲染')打印了几次。
    // setIndex(1);
    // setIndex(2);
    // setIndex(3);
    // 原因：队列，多次调用set函数且对同个值进行修改时，拿到最后更新的值，再通知组件render。性能优化了组件只渲染一次，但会引发下面问题。
    // 3.引发的问题，关注视图的值。
    // setIndex(index + 1);
    // setIndex(index + 1);
    // setIndex(index + 1);
    // 视图的值为什么不是3？原因：叠加无效，相同的函数会被认为是重复性操作，只执行第一个，后续被阻断
    // 4.解决方案-更新函数：即传入一个函数，函数的参数是上一个值，返回一个新的值
    setIndex((index) => index + 1);
    setIndex((index) => index + 1);
    setIndex((index) => index + 1);
    console.log(index, 'index');
  };

  return (
    // <>
    //   <div>
    //     <a href="https://vite.dev" target="_blank">
    //       <img src={viteLogo} className="logo" alt="Vite logo" />
    //     </a>
    //     <a href="https://react.dev" target="_blank">
    //       <img src={reactLogo} className="logo react" alt="React logo" />
    //     </a>
    //   </div>
    //   <h1>Vite + React</h1>
    //   <div className="card">
    //     <button onClick={() => setCount((count) => count + 1)}>
    //       count is {count}
    //     </button>
    //     <p>
    //       Edit <code>src/App.tsx</code> and save to test HMR
    //     </p>
    //   </div>
    //   <p className="read-the-docs">
    //     Click on the Vite and React logos to learn more
    //   </p>
    // </>
    <>
      <div>
        {/* <button onClick={setCount}>点击我</button> */}
        <button onClick={(e) => setCountT('aaaa')}>事件</button>
        <div id={id} className={className}>
          绑定id和class
        </div>
        <div className={`${className} cls1 cls2`}>使用模板字符串添加多个类名</div>
        <div dangerouslySetInnerHTML={{ __html: htmlString }}></div>
        <div>
          {arr.map((item) => {
            return <div key={item.id}>{item.name}</div>;
          })}
        </div>
        <h1>7.hooks</h1>
        <h2>7-1.useState</h2>
        <ul>
          <li>
            <span>简单数据类型：</span>
            <div>{str}</div>
            <button onClick={handleClick}>点击-改变简单数据类型</button>
            <div>{bool ? '开' : '关'}</div>
            <button onClick={handleClickBool}>点击-改变简单数据类型</button>
          </li>
          <li>
            <span>复杂数据类型：</span>
            <div>
              <b>数组</b>
            </div>
            <div>{list}</div>
            <button onClick={() => handleClickList()}>点击-改变</button>
            <div>{num}</div>
            <button onClick={() => handleClickList('sort')}>点击-排序</button>
            <div>
              <b>对象</b>
            </div>
            <div>名字：{obj.name}</div>
            <div>年龄：{obj.age}</div>
            <div>日期：{obj.date}</div>
            <button onClick={() => handleClickObj()}>点击-改名字</button>
          </li>
          <li>useState更新机制</li>
          <div>{index}</div>
          <button onClick={handleClickIndex}>更改index</button>
        </ul>
      </div>
    </>
  );
}

export default App;
